package com.bxs;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bxs.config.IdsConfig;
import com.bxs.dao.DataSaveEngine;
import com.bxs.dao.db.NotifyHandler;
import com.bxs.dao.db.SaveMsgToDBHandler;
import com.bxs.dao.email.EmailHandler;
import com.bxs.detector.BaseDetector;
import com.bxs.detector.DetectorEngine;
import com.bxs.detector.impl.CustomRuleDetector;
import com.bxs.detector.impl.PatternDetector;
import com.bxs.detector.impl.ProtocolFieldDetector;
import com.bxs.global.LogLevel;
import com.bxs.handler.BasePacketHandler;
import com.bxs.handler.FrequentPacketHandler;
import com.bxs.handler.HandlerManager;
import com.bxs.mapper.RuleMapper;
import com.bxs.pojo.NetWorkInterfaceInfo;
import com.bxs.pojo.BaseRule;
import com.bxs.sniffer.BaseSniffer;
import com.bxs.sniffer.FilterManager;
import lombok.extern.slf4j.Slf4j;
import org.pcap4j.core.*;
import org.pcap4j.packet.IpPacket;
import org.pcap4j.packet.namednumber.IpNumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author dream
 * @title: IdsManager
 * @projectName ids_v0_1
 * @description: TODO
 */
@Slf4j
@Component
public class IdsManager {
    // 配置类
    @Autowired
    IdsConfig idsConfig;

    // 应用实例
    private static volatile IdsManager mIdsManager;

    // 互斥锁
    private Lock lock = new ReentrantLock();

    // ids运行状态， 0，关闭，1，运行中，-1异常终止
    private int status = 0;
    private boolean init_status = false;

    // 嗅探器
    @Autowired
    public BaseSniffer sniffer;

    // 数据包处理器管理器
    HandlerManager handlerManager = null;
    // 数据包预处理器实例
    @Autowired
    FrequentPacketHandler frequentPacketHandler;


    // 包检测器管理器
    DetectorEngine detectorEngine = null;
    // 数据处理器管理器
    DataSaveEngine dataSaveEngine = null;
    // 数据处理器实例
    @Autowired
    NotifyHandler notifyHandler;
    @Autowired
    SaveMsgToDBHandler saveMsgToDBHandler;
    @Autowired
    EmailHandler emailHandler;

    @Autowired
    RuleMapper ruleMapper;

    // 监视网卡ip
    public String monitorAddress = null;

    // 线程池
//    BlockingQueue<Runnable> queue = new LinkedBlockingQueue();
//    public ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 15,
//            5, TimeUnit.MINUTES, queue);

    // 具体实例化在嗅探器中进行
    public ThreadPoolExecutor threadPoolExecutor = null;
    // 主机接口信息（）
    private List<NetWorkInterfaceInfo> netWorkInterfaceInfoList = null;

    // 单例模式(通过spring框架进行管理)
    private IdsManager() throws IOException, PcapNativeException {
        // 构造函数，加载设备网络接口信息（测试时不用，测试某些接口是否可用耗时过长，影响调试速度）
//        InterfacesService interfacesService = new InterfacesService();
//        netWorkInterfaceInfoList = interfacesService.getAllInterfaces();
    }
    // 加载对象实例(使用spring该方法没必要)
    public static IdsManager getInstance() throws IOException, PcapNativeException {
        if(mIdsManager == null){
            synchronized (IdsManager.class){
                mIdsManager = new IdsManager();
            }
        }
        return mIdsManager;
    }

    public void loadConfig(){
        loadConfig(idsConfig.defaultFile);
    }
    public void loadConfig(String filename){
        this.idsConfig = new IdsConfig(new File(filename));
    }

    public List<NetWorkInterfaceInfo> getNetWorkInterfaceInfoList() {
        return netWorkInterfaceInfoList;
    }

    // 初始化
    public void init() throws PcapNativeException, NotOpenException {
        if (this.idsConfig == null){
            loadConfig();
        }
        this.monitorAddress = idsConfig.interfaceAddressName;
        if(this.monitorAddress == null) {
            // 不存在监听的网卡地址，抛出异常
            throw new RuntimeException("not set address");
        }
        // TODO，配置应用
        // 1， 装配嗅探器，通过spring管理装配对象，检查
        if(sniffer == null){
            throw new NullPointerException("sniffer init error, null");
        }
        // 2、装配数据包处理器(数据包的检测、处理、日志等将由处理器链完成)
        handlerManager = new HandlerManager(sniffer.dumper);
        handlerManager.register(frequentPacketHandler);       // 注册频率检测处理器执行
        // 3、嗅探器中装配上预处理器
        sniffer.setHandlerManager(handlerManager);
        // 4、抓包过滤器（抓包过滤器有嗅探器自身去加载，不在应用主入口获取）
//        FilterManager filterManager = new FilterManager();
//        filterManager.addFilter(new TcpFilter());
//        sniffer.filterManager = filterManager;
        // 5、回调监听器(嗅探器和回调对象在整个IDS应用实例中只有一个，不用考虑线程安全的问题，但是后面的过滤器处理器链需要考虑线程安全的问题)
        PacketListener listener = new PacketListener() {
            @Override
            public void gotPacket(PcapPacket pcapPacket) {
                IpPacket ipPacket = pcapPacket.get(IpPacket.class);
                if (ipPacket == null){
                    System.out.println("get non ip packet");
//                    return;
                }else {
                    System.out.println("receive packet..., protocol:" + ipPacket.getHeader().getProtocol().valueAsString()
                            + ", srcIp:" + ipPacket.getHeader().getSrcAddr().getHostName() + ", dstIp: " + ipPacket.getHeader().getDstAddr().getHostName()
                    );
                }
                try {
                    if(idsConfig.isSave){
                        // 写入到文件
                        PcapDumper packetDumper = sniffer.dumper;
                        if(packetDumper == null){
                            log.error("haven't configure dumper, dump packet error");
                        }else {
                            packetDumper.dump(pcapPacket, Instant.now());
                            log.info("dump packet finished");
                        }
                    }
                } catch (NotOpenException e) {
                    log.error("packet dump error: " + pcapPacket);
                    e.printStackTrace();
                }
                // 构建任务
                PacketHandlerRunner packetHandlerRunner = new PacketHandlerRunner();
                // 分发到多个线程进行处理的数据包
                packetHandlerRunner.pcapPacket = pcapPacket;
                // 数据包dumper（嗅探器是单线程部分）
                packetHandlerRunner.packetDumper = sniffer.dumper;
                // 数据包预处理器
                packetHandlerRunner.handlerManager = handlerManager;
//                packetHandlerRunner.detectorEngine = detectorEngine1;
                // 数据包检测器
                packetHandlerRunner.detectorEngine = detectorEngine;
                // 数据存储器
                packetHandlerRunner.dataSaveEngine = dataSaveEngine;
                if (threadPoolExecutor.isShutdown())return;
                // 分发线程执行检测任务
                packetHandlerRunner.run();
//                threadPoolExecutor.submit(packetHandlerRunner);
            }
        };
        sniffer.callbackListener = listener;
        // 6、装配检测引擎(未在ids入口装配时使用的默认配置)
        if(detectorEngine == null) detectorEngine = new DetectorEngine();
        detectorEngine.autoConfigureDetector();
        // 加载检测规则
        List<BaseRule> baseRules = ruleMapper.selectList(new QueryWrapper<>());
        detectorEngine.setRules(baseRules);

        // 7、装配数据处理器(未在ids入口装配时使用的默认配置)
        if(dataSaveEngine == null) dataSaveEngine = new DataSaveEngine();
        // 装配检测结果数据处理器
        dataSaveEngine.register(saveMsgToDBHandler);
        // 装配邮件处理器，用户邮件通知
        dataSaveEngine.register(emailHandler);
        // 装配通知处理器
        dataSaveEngine.register(notifyHandler);

        init_status = true;
    }

    // 启动
    public void start() throws PcapNativeException, InterruptedException, NotOpenException, IOException {
        if(!init_status)init();
        if(status == 1){
            return; // 已运行，返回
        }
        // 开始启动
        BlockingQueue<Runnable> queue = new LinkedBlockingQueue();
        threadPoolExecutor = new ThreadPoolExecutor(15, 15,
                5, TimeUnit.MINUTES, queue);
        sniffer.executorService = threadPoolExecutor;
//        threadPoolExecutor = sniffer.executorService;
        log.info("init ids thread pool finished...");
        sniffer.executorService.submit(()->{
            try {
                sniffer.start();
            } catch (PcapNativeException e) {
                e.printStackTrace();
            } catch (NotOpenException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        });

//        threadPoolExecutor.submit(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    System.out.println("sniffer start...");
//                    sniffer.start();
//                    System.out.println("sniffer start finished...");
//                } catch (PcapNativeException e) {
//                    log.error(e.getMessage(), e);
//                } catch (NotOpenException e) {
//                    log.error(e.getMessage(), e);
//                } catch (InterruptedException e) {
//                    log.error(e.getMessage(), e);
//                } catch (UnknownHostException e) {
//                    log.error(e.getMessage(), e);
//                }
//            }
//        });
        updateStatus(1);
        handlerManager.packetDumper = sniffer.dumper;
        log.info("start sniffer finished");
    }

    // 关闭
    public void close() throws NotOpenException {
        System.out.println("start stop ids...");
        System.out.println(sniffer == null);
        // 关闭嗅探器
        if(sniffer != null) {
            sniffer.stop();
        }
        // 关闭正在工作的线程
        if(threadPoolExecutor != null) threadPoolExecutor.shutdown();
        updateStatus(0);
        init_status = false;    // 关闭时配置信息清空
        log.info("ids close finished");
    }

    public void restart() throws PcapNativeException, InterruptedException, NotOpenException, IOException {
        close();
        start();
    }

    // 更新应用运行状态
    public void updateStatus(int status){
        this.lock.lock();
        this.status = status;
        this.lock.unlock();
    }

    // ids操作接口: 添加新的包处理器
    public void addPacketHandler(BasePacketHandler packetHandler){
        handlerManager.register(packetHandler);
    }

    // ids操作接口：添加新的检测器
    public void addPacketDetector(BaseDetector detector){

    }

    // 获取状态
    public int getStatus(){
        return status;
    }

    // 获取当前ids线程池工作状态
    public Map<String, Object> getThreadPoolStatus(){
        Map<String, Object> status = new HashMap<>();
        status.put("idsRunning", this.status);
        status.put("monitor_address", this.monitorAddress);
        if(threadPoolExecutor == null)return status;
        status.put("taskNum", threadPoolExecutor.getTaskCount());
        status.put("taskOfQueueNum", threadPoolExecutor.getQueue().size());   // 带处理任务数
        status.put("completedTaskNum", threadPoolExecutor.getCompletedTaskCount());
        status.put("activeWorkerNum", threadPoolExecutor.getActiveCount());

        try {
            if(sniffer != null && sniffer.handle != null) {
                PcapStat stats = sniffer.handle.getStats();
                status.put("receive", stats.getNumPacketsReceived());
                status.put("captured", stats.getNumPacketsCaptured());
                status.put("dropped", stats.getNumPacketsDropped());
            }
        } catch (PcapNativeException e) {
            e.printStackTrace();
        } catch (NotOpenException e) {
            e.printStackTrace();
        }

        return status;
    }
}
